#include <u8Matrix.h>

#ifdef USE_UCS2
int U8Matrix::one_utf8ucs2(uint16_t *dest, uint8_t *src)
{
    if(src[0] < 80)
    {
        *dest = src[0];
        return 1;
    }
    else if((src[0] & 0xe0) == 0xc0)
    {
        *dest = (src[0]&0x1f)<<6;
        *dest |= src[1]&0x3f;
        return 2;
    }
    else if((src[0] & 0xf0) == 0xe0)
    {
        *dest = (src[0]&0x0f)<<12;
        *dest |= (src[1]&0x3f)<<6;
        *dest |= src[2]&0x3f;
        return 3;
    }
    
    return 0;
}

void U8Matrix::utf8ucs2(uint16_t *dest, uint8_t *src)
{
    while(*src)
    {
        src += one_utf8ucs2(dest, src);
        dest++;
    }
    *dest = 0;
}

int U8Matrix::one_ucs2utf8(uint8_t *dest, uint16_t code)
{
    if((code) < 0x80)
    {
        dest[0] = (uint8_t)(code);
        return 1;
    }
    else if(code < 0x800)
    {
        dest[0] = 0xc0 | (code >> 6);
        dest[1] = 0x80 | (code & 0x3f);
        return 2;
    }
    else
    {
        dest[0] = 0xe0 | (code >> 12);
        dest[1] = 0x80 | ((code >> 6) & 0x3f);
        dest[2] = 0x80 | (code & 0x3f);
        return 3;
    }
}

void U8Matrix::ucs2utf8(uint8_t *dest, uint16_t *src)
{
    while(*src)
    {
        dest += one_ucs2utf8(dest, *src);
        src++;
    }
    *dest = 0;
}
#endif

void U8Matrix::begin(Adafruit_GFX &gfx)
{
    display = &gfx;
}

/*
void U8Matrix::setForegroundColor(uint16_t color)
{
    dtColor = color;
}

void U8Matrix::setBackgroundColor(uint16_t color)
{
    bgColor = color;
}
*/

void U8Matrix::setFont(const uint8_t *font)
{
    fontMatrix = font;
    mx = (TxtMatrix *)fontMatrix;
}

uint8_t *U8Matrix::locateAscii(uint16_t c)
{
    if (c < 32 || c > 126 || !mx)
    {
        return NULL;
    }

    return (uint8_t *)fontMatrix + mx->enMatrix + (c - 32) * (mx->hBytes>>1);
}

/**
 * @brief 取UTF-8字符点阵指针
 */
uint8_t *U8Matrix::locateUTF8(uint16_t cn)
{
    CnSeg *cnSeg;
    uint8_t *cnOff = NULL;

    if (!mx)
    {
        return NULL;
    }

    // 首先在分段里查找
    uint8_t *pSeg = (uint8_t *)fontMatrix + mx->cnSeg;
    for (int i = 0; i < mx->segCount; i++)
    {
        cnSeg = (CnSeg *)pSeg;

        if (cnSeg->fCode <= cn && cn <= cnSeg->tCode) // 若在这里
        {
            cnOff = (uint8_t *)fontMatrix + cnSeg->cnMatrix + (cn - cnSeg->fCode) * mx->hBytes;
            break;
        }
        pSeg += 8; // 每段信息占8个字节
    }

    if (!cnOff) // 不在分段里，要在落单汉字里找
    {
        uint8_t *oOff = (uint8_t *)fontMatrix + mx->cnMatrix;
        for (uint16_t code = 0; code != 0xffff; oOff += (mx->hBytes + 2))
        {
            code = *((uint16_t *)oOff);
            if (code == cn)
            {
                cnOff = oOff + 2;
            }
        }
    }

    return cnOff;
}

void U8Matrix::drawBitmap(int cx, int cy, int w, int h, uint8_t *bitMap, uint16_t dColor)
{
    if (bitMap)
    {
        for (h += cy, w += cx; cy < h; cy++)
        {
            uint8_t m = 0x80;
            for (int x = cx; x < w; x++)
            {
                if ((*bitMap) & m)
                {
                    display->drawPixel(x, cy, dColor);
                }

                m >>= 1;
                if (!m)
                {
                    m = 0x80;
                    bitMap++;
                }
            }
            if (m != 0x80)
                bitMap++; // 抛弃剩余位
        }
    }
}

#ifdef USE_UCS2
void U8Matrix::drawUTF8(int x, int y, char *str)
{
    uint16_t *code = (uint16_t *)str;
    y -= 14; // 与u8g2差一个字高
    int hw = (mx->width >> 1);
    while ((*code) != 0)
    {
        int w = mx->width;
        if ((*code) < 0x80)
        {
            w = hw;
            drawBitmap(x, y, w, mx->height, locateAscii(*code));
        }
        else
        {
            drawBitmap(x, y, w, mx->height, locateUTF8(*code));
        }
        x += w;

        code++;
    }
}

int U8Matrix::getUTF8Width(char *str)
{
    int w = 0;
    int hw = (mx->width >> 1);
    uint16_t *code = (uint16_t *)str;
    while ((*code) != 0)
    {
        w += (*code) < 0x80 ? hw : mx->width;
        code++;
    }

    return w;
}
#else
/**
 * @brief 计算UTF-8字符占字节数，并抽取首字节有效位
 */
int utf8Len(uint8_t *p)
{
    int u;

    if ((*p) < 0xC0)
    {
        u = 1;
    }
    else if ((*p) < 0xE0)
    {
        (*p) &= 0x1F;
        u = 2;
    }
    else if ((*p) < 0xF0)
    {
        (*p) &= 0x0F;
        u = 3;
    }
    else if ((*p) < 0xF8)
    {
        (*p) &= 0x07;
        u = 4;
    }
    else if ((*p) < 0xFC)
    {
        (*p) &= 0x03;
        u = 5;
    }
    else
    {
        (*p) &= 0x01;
        u = 6;
    }

    return u;
}

void U8Matrix::drawUTF8(int x, int y, char const *str)
{
    uint32_t e;
    uint8_t c, u;

    y -= 14; // 与u8g2差一个字高
    int hw = (mx->width >> 1);
    while ((*str) != 0)
    {
        c = *str;
        u = utf8Len(&c);
        e = c;

        while (--u)
        {
            e <<= 6;
            str++;
            e += (*str) & 0x3F;
        }

        int w = mx->width;
        if (e < 0xC0)
        {
            w = hw;
            drawBitmap(x, y, w, mx->height, locateAscii(e));
        }
        else
        {
            drawBitmap(x, y, w, mx->height, locateUTF8(e));
        }
        x += w;

        str++;
    }
}

int U8Matrix::getUTF8Width(char *str)
{
    int w = 0;
    uint8_t c, u;

    while ((*str) != 0)
    {
        c = *str;
        u = utf8Len(&c);
        if (u > 1)
        {
            str += u;
            w += mx->width;
        }
        else
        {
            str++;
            w += (mx->width>>1);
        }
    }

    return w;
}
#endif